
#include <stdio.h>

#include <avr/io.h>
#include "Arduino.h"

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "debug.h"
#include "time.h"

#include "cmd.h"
#include "i2c.h"
#include "lcd.h"
#include "sdcard.h"

#define CMD_QUEUE_DEPTH  4
//
// In Ticks: small because we're polling buttons for now
//
#define CMD_QUEUE_DELAY getTicksFromMillis(100)
//#define LOGGER_BUFFSIZE 16

QueueHandle_t CmdQueue;

//
// Using a 5V Arduino, and connecting the sensor directly into an 
// Analog pin, use these formulas to turn the 10-bit analog reading 
// into a temperature:
//
//    Voltage at pin in milliVolts = (reading from ADC) * (5000/1024) 
//
// This formula converts the number 0-1023 from the ADC into 0-5000mV (= 5V)
//
// Then, to convert millivolts into temperature, use this formula:
//
//    Centigrade temperature = [(analog voltage in mV) - 500] / 10
//
#ifndef _AREF_3_3_
//
// For better results, using the 3.3v reference voltage as ARef instead 
// of the 5V will be more precise and less noisy
//
#define aref_voltage 5.0

//
// TMP36 Pin Variables
//
//  the analog pin the TMP36's Vout (sense) pin is connected to the 
//  resolution is 10 mV / degree centigrade with a 500 mV offset to 
//  allow for negative temperatures
//
int tempPin = 0;
#else
//
// Sensor test sketch:
// for more information see http://www.ladyada.net/make/logshield/lighttemp.html
//
#define aref_voltage 3.3 // we tie 3.3V to ARef and measure it with a multimeter!
//
// TMP36 Pin Variables:
//
//  the analog pin the TMP36's Vout (sense) pin is connected to the 
//  resolution is 10 mV / degree centigrade with a 500 mV offset to 
//  allow for negative temperatures
//
int tempPin = 1; 
#endif


//
// software serial #1: TX = digital pin 2, RX = digital pin 3
//
//SoftwareSerial serial(2, 3);


//
// WiFi shield info:
//
// The Arduino communicates with the processor WiFi shield with the 
// microSD card by SPI (Eurotherm the ICSP bus) that is on pins 11, 12 
// and 13 at Uno. The pin 10 is used to select the HDG104 and pin 4 to 
// the microSD card(i dont need the pin 4 cause i wont use SD). These 
// pins can not be used for input and output. The digital pin 7 is used 
// for initialization of the communication protocol between the shield 
// and Arduino WiFi and should not be used.
//

//#include <SD.h>
//
// Macro SD card slot with SPI interface uses pins: D4 (select), D11, D12, D13 
//


//File logfile;

//
// Ethernet uses pins: D10 (select), D11, D12, D13
//

//#define chipSelect 10

// ===================================================================
//   vSetDigitalOutput
// ===================================================================
void vSetDigitalOutput (int task)
{
  //PRINTF("TaskSwitch %d \n", task);
}

#ifdef _USE_ADC_
// ===================================================================
//   ReadADC
// ===================================================================
uint16_t ReadADC (uint8_t ADCchannel)
{
  //
  // Select ADC channel with safety mask:
  //
  // Use a mask (0b00001111) which protects from unintentional alteration 
  // of ADMUX register.
  //
  ADMUX = (ADMUX & 0xF0) | (ADCchannel & 0x0F);
  //
  // Single conversion mode: start single conversion by setting ADSC bit 
  // in ADCSRA register. This bit remains high until conversion is 
  // complete.
  //
  ADCSRA |= (1<<ADSC);
  //
  // wait until ADC conversion is complete
  //
  while( ADCSRA & (1<<ADSC) );

  return ADC;
}
#endif // _USE_ADC_

// ===================================================================
//   vTemperatureTask
//
//   Reading luminosity sensor value
// ===================================================================
static void vTemperatureTask(void * pvParameters) 
{
#ifdef _USE_ADC_
  double t0;
#endif

  //char buffer[LOGGER_BUFFSIZE];
  //char c;
  //int bufferidx = 0;

  //vTaskSetApplicationTaskTag(NULL, (BaseType_t(*)(void *)) 2);

  while(1) {

    uint8_t command = CMD_NONE;

    CMD_UpdateDisplay();

#ifdef _USE_ADC_

#define POT 10000

    t0 = (double)POT/1024*ReadADC(0);
    
    //
    // Send t0 value to terminal
    //
    PRINTF ("Temperature: %u\n", (uint16_t)t0);
#else
    //
    // Read the value from the temperature sensor
    //
    int reading = analogRead(tempPin);
    //
    //
    //
    PRINTF ("Temp reading = %d\n", reading);
    //
    // convert that reading to voltage
    //
    float voltage = reading * aref_voltage;
    voltage /= 1024.0;
    //
    // print out the voltage
    //
    //PRINTF ("Voltage: %f Volts\n", voltage);
    //
    // Print out the temperature: converting from 10 mv per degree 
    // with 500 mV offset to degrees ((voltage - 500mV) times 100)
    //
    float temperatureC = (voltage - 0.5) * 100 ;
    PRINTF ("Temperature: %f degrees C\n", temperatureC);
    //
    // now convert to Fahrenheits
    //
    float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0;
    PRINTF ("Temperature: %f degrees F\n", temperatureF);
#endif

#if 0
    //
    // read into program buffer, increment index
    //
    if (Serial.available()) {
      c = Serial.read();
      SD_write (c);
    }
#endif // 0

    //vTaskDelay(configTICK_RATE_HZ); //10ms

    if (xQueueReceive(CmdQueue, &command, CMD_QUEUE_DELAY) == pdTRUE) {

      //PRINTF (" *** Received command 0x02%x ... \n", command);

      CMD_handle(command);
    }
    else {
      PRINTF (" *** Temperature task timeout CMD_QUEUE_DELAY=%u ... \n", CMD_QUEUE_DELAY);

      // Temporary while not using the queue below
      command = PollButtons ();
      CMD_handle(command);
    }

    

  }

  return;
}


#ifdef _USE_ADC_
// ===================================================================
//   InitADC
// ===================================================================
void InitADC ()
{
  //
  // Select Vref=AVcc
  //
  ADMUX |= (1<<REFS0);
  //
  // Set prescaller to 128 and enable ADC.
  //
  // AVR is clocked at 16MHz. We use 128 scaling factor by setting 
  // ADPS0, ADPS1 and ADPS2 bits in ADCSRA register. 
  // This gives 16000000/128 = 125kHz of ADC clock.
  // Enable ADC module by setting ADEN bit in ADCSRA register.
  //
  ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN);  

  return;
}
#endif // _USE_ADC_

// ===================================================================
//   setup
// ===================================================================
void setup ()
{
  // Insure malloc works in tasks
  //__malloc_heap_end = (char*)RAMEND;

  //
  // Initialization of the serial communication with 9600kbits as baud rate
  //
  usart0_init ();

  //
  // This code detects the address of the I2C devices; we're looking for the
  // LCD.
  //
  I2C_setup ();

  //
  // Initialize the LCD
  //
  LCD_setup();

  //
  // Buttons and Ethernet setup
  //
  CMD_setup ();

  //
  // Initialiuze SD Card Stuff
  //
  SD_setup();

#ifdef _USE_ADC_
  InitADC();
#else
#ifdef _AREF_3_3_
  // If you want to set the aref to something other than 5v
  analogReference(EXTERNAL);
#endif
#endif

  //
  // create temperature measurement task
  //
  xTaskCreate(vTemperatureTask ,
	      "T",
	      //configMINIMAL_STACK_SIZE + 100 + LOGGER_BUFFSIZE*sizeof(char),
	      configMINIMAL_STACK_SIZE + 100,
	      NULL,
	      tskIDLE_PRIORITY + 1 ,
	      NULL ) ;

  //
  // Create command queue
  //
  CmdQueue = xQueueCreate (CMD_QUEUE_DEPTH, sizeof(uint8_t));
  if ( CmdQueue == 0 ) {
    // Queue was not created and must not be used.
    PRINTF ("Failed to create a Cmd queue, aborting ...\n");
    ASSERT(__FILE__,__LINE__);
  }

  PRINTF ("(c) 2014 Arthur: Temperature Data Logger\n");

  return;
}

/**************************************************************************//**
 * \fn int main(void)
 *
 * \brief Main function.
 *
 * \return
 ******************************************************************************/
int main(void)
{
  //
  // Arduino pattern: /usr/share/arduino/hardware/arduino/cores/arduino/main.cpp
  //

  init();

  //#if defined(USBCON)
  //  USB.attach();
  //#endif

  setup();
  //for (;;) {
  //  loop();
  //  if (serialEventRun) serialEventRun();
  //}
  //
  // We start FreeRTOS here
  //
  vTaskStartScheduler ();
  
  return 0;
}

